package net.simflow.swf.analyzer.fileprinter;

import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedHashMap;
import java.util.Map.Entry;
import java.util.TreeMap;

import net.simflow.swf.analyzer.bgnetwork.data.BGNode;
import net.simflow.swf.analyzer.bgnetwork.stats.data.BGNetworkStats;

public class BGNetworkStatsFilePrinter {
	private static final LinkedHashMap<String, Boolean> DEFAULT_CONFIG = new LinkedHashMap<String, Boolean>();
	static {
		DEFAULT_CONFIG.put(BGNetworkStats.NETWORK_NAME, true);
		DEFAULT_CONFIG.put(BGNetworkStats.NETWORK_FLOW_NEIGHBOR, true);
		DEFAULT_CONFIG.put(BGNetworkStats.NETWORK_SERVICE_NEIGHBOR, true);
		DEFAULT_CONFIG.put(BGNetworkStats.NETWORK_FLOW_DEGREE, true);
		DEFAULT_CONFIG.put(BGNetworkStats.NETWORK_SERVICE_DEGREE, true);

		DEFAULT_CONFIG.put(BGNetworkStats.FLOW_PART_NAME, true);
		DEFAULT_CONFIG.put(BGNetworkStats.FLOW_PART_NEIGHBOR, true);
		DEFAULT_CONFIG.put(BGNetworkStats.FLOW_PART_DEGREE, true);

		DEFAULT_CONFIG.put(BGNetworkStats.SERVICE_PART_NAME, true);
		DEFAULT_CONFIG.put(BGNetworkStats.SERVICE_PART_NEIGHBOR, true);
		DEFAULT_CONFIG.put(BGNetworkStats.SERVICE_PART_DEGREE, true);
	}

	private static BGNetworkStatsFilePrinter instance = new BGNetworkStatsFilePrinter();

	private BGNetworkStatsFilePrinter() {
	}

	public static BGNetworkStatsFilePrinter getInstance() {
		return instance;
	}

	public void print(FilePrinter p, BGNetworkStats nstats) {
		if (p == null) {
			return;
		}
		if (nstats == null) {
			return;
		}

		p.print(FilePrinter.NEW_LINE + "BG Network Info:");
		for (Entry<String, Boolean> en : DEFAULT_CONFIG.entrySet()) {
			if (!en.getValue()) {
				continue;
			}
			String title = en.getKey();
			switch (title) {
			case BGNetworkStats.NETWORK_NAME:
				this.printNameString(p, title, nstats.getNetworkName());
				break;
			case BGNetworkStats.NETWORK_FLOW_NEIGHBOR:
				this.printNeighborString(p, title,
						nstats.getNetworkFlowNeighborMap());
				break;
			case BGNetworkStats.NETWORK_SERVICE_NEIGHBOR:
				this.printNeighborString(p, title,
						nstats.getNetworkServiceNeighborMap());
				break;
			case BGNetworkStats.NETWORK_FLOW_DEGREE:
				this.printDegreeDistributionString(p, title,
						nstats.getNetworkFlowDegreeDistribution());
				break;
			case BGNetworkStats.NETWORK_SERVICE_DEGREE:
				this.printDegreeDistributionString(p, title,
						nstats.getNetworkServiceDegreeDistribution());
				break;
			case BGNetworkStats.FLOW_PART_NAME:
				this.printNameString(p, title, nstats.getFlowNetworkName());
				break;
			case BGNetworkStats.FLOW_PART_NEIGHBOR:
				this.printNeighborString(p, title, nstats.getFlowNeighborMap());
				break;
			case BGNetworkStats.FLOW_PART_DEGREE:
				this.printDegreeDistributionString(p, title,
						nstats.getFlowNetworkDegreeDistribution());
				break;
			case BGNetworkStats.SERVICE_PART_NAME:
				this.printNameString(p, title, nstats.getServiceNetworkName());
				break;
			case BGNetworkStats.SERVICE_PART_NEIGHBOR:
				this.printNeighborString(p, title,
						nstats.getServiceNeighborMap());
				break;
			case BGNetworkStats.SERVICE_PART_DEGREE:
				this.printDegreeDistributionString(p, title,
						nstats.getServiceNetworkDegreeDistribution());
				break;
			}
		}
	}

	public void printNameString(FilePrinter p, String title, String name) {
		if (name == null) {
			return;
		}
		p.print(FilePrinter.NEW_LINE + title + ":" + FilePrinter.TAB + name);
	}

	public void printNeighborString(FilePrinter p, String title,
			HashMap<BGNode, HashSet<BGNode>> map) {
		if (map == null) {
			return;
		}

		boolean is = true;

		for (Entry<BGNode, HashSet<BGNode>> en : map.entrySet()) {
			if (is) {
				p.print(FilePrinter.NEW_LINE + title + ":");
				is = false;
			}
			p.print(FilePrinter.TAB + en.getKey().getNameInBG() + "("
					+ en.getValue().size() + "):");
			for (BGNode node : en.getValue()) {
				p.print(" " + node.getNameInBG() + ";");
			}
		}
	}

	public void printDegreeDistributionString(FilePrinter p, String title,
			TreeMap<Integer, HashSet<BGNode>> map) {
		if (map == null) {
			return;
		}
		map.comparator();

		boolean is = true;

		for (Entry<Integer, HashSet<BGNode>> en : map.descendingMap()
				.entrySet()) {
			if (is) {
				p.print(FilePrinter.NEW_LINE + title + ":");
				is = false;
			}
			p.print(FilePrinter.TAB + en.getKey() + " (" + en.getValue().size()
					+ "):");
			for (BGNode node : en.getValue()) {
				p.print(" " + node.getNameInBG() + ";");
			}
		}
	}
}
